<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<title>libspotify: jukebox.c</title>

<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="doxygen.css" rel="stylesheet" type="text/css" />



</head>
<body>
<div id="top"><!-- do not remove this div! -->


<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  
  
  <td style="padding-left: 0.5em;">
   <div id="projectname">libspotify
   
   </div>
   
  </td>
  
  
  
 </tr>
 </tbody>
</table>
</div>

<!-- Generated by Doxygen 1.8.0 -->
  <div id="navrow1" class="tabs">
    <ul class="tablist">
      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
      <li><a href="modules.html"><span>Modules</span></a></li>
      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
      <li><a href="files.html"><span>Files</span></a></li>
      <li><a href="examples.html"><span>Examples</span></a></li>
    </ul>
  </div>
</div>
<div class="header">
  <div class="headertitle">
<div class="title">jukebox.c</div>  </div>
</div><!--header-->
<div class="contents">
<p>The jukebox.c example shows how you can use playback and playlist functions.</p>
<div class="fragment"><pre class="fragment">
<span class="preprocessor">#include &lt;errno.h&gt;</span>
<span class="preprocessor">#include &lt;libgen.h&gt;</span>
<span class="preprocessor">#include &lt;pthread.h&gt;</span>
<span class="preprocessor">#include &lt;stdint.h&gt;</span>
<span class="preprocessor">#include &lt;stdio.h&gt;</span>
<span class="preprocessor">#include &lt;stdlib.h&gt;</span>
<span class="preprocessor">#include &lt;string.h&gt;</span>
<span class="preprocessor">#include &lt;unistd.h&gt;</span>
<span class="preprocessor">#include &lt;sys/time.h&gt;</span>

<span class="preprocessor">#include &lt;libspotify/api.h&gt;</span>

<span class="preprocessor">#include &quot;audio.h&quot;</span>


<span class="comment">/* --- Data --- */</span>
<span class="keyword">extern</span> <span class="keyword">const</span> uint8_t g_appkey[];
<span class="keyword">extern</span> <span class="keyword">const</span> <span class="keywordtype">size_t</span> g_appkey_size;

<span class="keyword">static</span> audio_fifo_t g_audiofifo;
<span class="keyword">static</span> pthread_mutex_t g_notify_mutex;
<span class="keyword">static</span> pthread_cond_t g_notify_cond;
<span class="keyword">static</span> <span class="keywordtype">int</span> g_notify_do;
<span class="keyword">static</span> <span class="keywordtype">int</span> g_playback_done;
<span class="keyword">static</span> <a class="code" href="group__types.html#ga70dd19c6f824cf6a159575aa4c128b53" title="Representation of a session.">sp_session</a> *g_sess;
<span class="keyword">static</span> <a class="code" href="group__types.html#ga1bcf54cbc117a20ab2c15e59eb3a8174" title="A playlist handle.">sp_playlist</a> *g_jukeboxlist;
<span class="keyword">const</span> <span class="keywordtype">char</span> *g_listname;
<span class="keyword">static</span> <span class="keywordtype">int</span> g_remove_tracks = 0;
<span class="keyword">static</span> <a class="code" href="group__types.html#ga47bbd2262f0c8b5d7147af7d62198e48" title="A track handle.">sp_track</a> *g_currenttrack;
<span class="keyword">static</span> <span class="keywordtype">int</span> g_track_index;


<span class="keyword">static</span> <span class="keywordtype">void</span> try_jukebox_start(<span class="keywordtype">void</span>)
{
    <a class="code" href="group__types.html#ga47bbd2262f0c8b5d7147af7d62198e48" title="A track handle.">sp_track</a> *t;

    <span class="keywordflow">if</span> (!g_jukeboxlist)
        <span class="keywordflow">return</span>;

    <span class="keywordflow">if</span> (!<a name="a0"></a><a class="code" href="group__playlist.html#ga684a3acc60f99b3b26488ed813ee5d23">sp_playlist_num_tracks</a>(g_jukeboxlist)) {
        fprintf(stderr, <span class="stringliteral">&quot;jukebox: No tracks in playlist. Waiting\n&quot;</span>);
        <span class="keywordflow">return</span>;
    }

    <span class="keywordflow">if</span> (<a class="code" href="group__playlist.html#ga684a3acc60f99b3b26488ed813ee5d23">sp_playlist_num_tracks</a>(g_jukeboxlist) &lt; g_track_index) {
        fprintf(stderr, <span class="stringliteral">&quot;jukebox: No more tracks in playlist. Waiting\n&quot;</span>);
        <span class="keywordflow">return</span>;
    }

    t = <a name="a1"></a><a class="code" href="group__playlist.html#ga7a03854fe6072476306780d23c6cac16">sp_playlist_track</a>(g_jukeboxlist, g_track_index);

    <span class="keywordflow">if</span> (g_currenttrack &amp;&amp; t != g_currenttrack) {
        <span class="comment">/* Someone changed the current track */</span>
        audio_fifo_flush(&amp;g_audiofifo);
        <a name="a2"></a><a class="code" href="group__session.html#ga91f2b527a7b02d688b8ef8b24060f70a">sp_session_player_unload</a>(g_sess);
        g_currenttrack = NULL;
    }

    <span class="keywordflow">if</span> (!t)
        <span class="keywordflow">return</span>;

    <span class="keywordflow">if</span> (<a name="a3"></a><a class="code" href="group__track.html#ga947c0f7755b0c4955ca0b0993db0f2b5">sp_track_error</a>(t) != <a name="a4"></a><a class="code" href="group__error.html#ggafd27986ce4cd9eeaeca8adda83c9eb6ba16cb277dc84328e4b2c0cf6d5a0c0b8d" title="No errors encountered.">SP_ERROR_OK</a>)
        <span class="keywordflow">return</span>;

    <span class="keywordflow">if</span> (g_currenttrack == t)
        <span class="keywordflow">return</span>;

    g_currenttrack = t;

    printf(<span class="stringliteral">&quot;jukebox: Now playing \&quot;%s\&quot;...\n&quot;</span>, <a name="a5"></a><a class="code" href="group__track.html#ga8eb423d3cc2cbfb743c7f23ffb8d0fad">sp_track_name</a>(t));
    fflush(stdout);

    <a name="a6"></a><a class="code" href="group__session.html#gac73bf2c569a43d824439b557d5e4b293">sp_session_player_load</a>(g_sess, t);
    <a name="a7"></a><a class="code" href="group__session.html#gab09b741570aa0330e9a0b1278ad518a5">sp_session_player_play</a>(g_sess, 1);
}

<span class="comment">/* --------------------------  PLAYLIST CALLBACKS  ------------------------- */</span>
<span class="keyword">static</span> <span class="keywordtype">void</span> tracks_added(<a class="code" href="group__types.html#ga1bcf54cbc117a20ab2c15e59eb3a8174" title="A playlist handle.">sp_playlist</a> *pl, <a class="code" href="group__types.html#ga47bbd2262f0c8b5d7147af7d62198e48" title="A track handle.">sp_track</a> * <span class="keyword">const</span> *tracks,
                         <span class="keywordtype">int</span> num_tracks, <span class="keywordtype">int</span> position, <span class="keywordtype">void</span> *userdata)
{
    <span class="keywordflow">if</span> (pl != g_jukeboxlist)
        <span class="keywordflow">return</span>;

    printf(<span class="stringliteral">&quot;jukebox: %d tracks were added\n&quot;</span>, num_tracks);
    fflush(stdout);
    try_jukebox_start();
}

<span class="keyword">static</span> <span class="keywordtype">void</span> tracks_removed(<a class="code" href="group__types.html#ga1bcf54cbc117a20ab2c15e59eb3a8174" title="A playlist handle.">sp_playlist</a> *pl, <span class="keyword">const</span> <span class="keywordtype">int</span> *tracks,
                           <span class="keywordtype">int</span> num_tracks, <span class="keywordtype">void</span> *userdata)
{
    <span class="keywordtype">int</span> i, k = 0;

    <span class="keywordflow">if</span> (pl != g_jukeboxlist)
        <span class="keywordflow">return</span>;

    <span class="keywordflow">for</span> (i = 0; i &lt; num_tracks; ++i)
        <span class="keywordflow">if</span> (tracks[i] &lt; g_track_index)
            ++k;

    g_track_index -= k;

    printf(<span class="stringliteral">&quot;jukebox: %d tracks were removed\n&quot;</span>, num_tracks);
    fflush(stdout);
    try_jukebox_start();
}

<span class="keyword">static</span> <span class="keywordtype">void</span> tracks_moved(<a class="code" href="group__types.html#ga1bcf54cbc117a20ab2c15e59eb3a8174" title="A playlist handle.">sp_playlist</a> *pl, <span class="keyword">const</span> <span class="keywordtype">int</span> *tracks,
                         <span class="keywordtype">int</span> num_tracks, <span class="keywordtype">int</span> new_position, <span class="keywordtype">void</span> *userdata)
{
    <span class="keywordflow">if</span> (pl != g_jukeboxlist)
        <span class="keywordflow">return</span>;

    printf(<span class="stringliteral">&quot;jukebox: %d tracks were moved around\n&quot;</span>, num_tracks);
    fflush(stdout);
    try_jukebox_start();
}

<span class="keyword">static</span> <span class="keywordtype">void</span> playlist_renamed(<a class="code" href="group__types.html#ga1bcf54cbc117a20ab2c15e59eb3a8174" title="A playlist handle.">sp_playlist</a> *pl, <span class="keywordtype">void</span> *userdata)
{
    <span class="keyword">const</span> <span class="keywordtype">char</span> *name = <a name="a8"></a><a class="code" href="group__playlist.html#ga61b7e33cc1aedb4e31a2af75ae0ac8cc">sp_playlist_name</a>(pl);

    <span class="keywordflow">if</span> (!strcasecmp(name, g_listname)) {
        g_jukeboxlist = pl;
        g_track_index = 0;
        try_jukebox_start();
    } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (g_jukeboxlist == pl) {
        printf(<span class="stringliteral">&quot;jukebox: current playlist renamed to \&quot;%s\&quot;.\n&quot;</span>, name);
        g_jukeboxlist = NULL;
        g_currenttrack = NULL;
        <a class="code" href="group__session.html#ga91f2b527a7b02d688b8ef8b24060f70a">sp_session_player_unload</a>(g_sess);
    }
}

<span class="keyword">static</span> <a name="_a9"></a><a class="code" href="structsp__playlist__callbacks.html">sp_playlist_callbacks</a> pl_callbacks = {
    .<a name="a10"></a><a class="code" href="structsp__playlist__callbacks.html#a16c3e5758f8f73f5900de4b88424f85e">tracks_added</a> = &amp;tracks_added,
    .tracks_removed = &amp;tracks_removed,
    .tracks_moved = &amp;tracks_moved,
    .playlist_renamed = &amp;playlist_renamed,
};


<span class="comment">/* --------------------  PLAYLIST CONTAINER CALLBACKS  --------------------- */</span>
<span class="keyword">static</span> <span class="keywordtype">void</span> playlist_added(<a class="code" href="group__types.html#ga45a2febbe167483e48dab8d606d462d7" title="A playlist container (playlist containing other playlists) handle.">sp_playlistcontainer</a> *pc, <a class="code" href="group__types.html#ga1bcf54cbc117a20ab2c15e59eb3a8174" title="A playlist handle.">sp_playlist</a> *pl,
                           <span class="keywordtype">int</span> position, <span class="keywordtype">void</span> *userdata)
{
    <a name="a11"></a><a class="code" href="group__playlist.html#gac90e08b7cf247c51a577ac3b763b6a6f">sp_playlist_add_callbacks</a>(pl, &amp;pl_callbacks, NULL);

    <span class="keywordflow">if</span> (!strcasecmp(<a class="code" href="group__playlist.html#ga61b7e33cc1aedb4e31a2af75ae0ac8cc">sp_playlist_name</a>(pl), g_listname)) {
        g_jukeboxlist = pl;
        try_jukebox_start();
    }
}

<span class="keyword">static</span> <span class="keywordtype">void</span> playlist_removed(<a class="code" href="group__types.html#ga45a2febbe167483e48dab8d606d462d7" title="A playlist container (playlist containing other playlists) handle.">sp_playlistcontainer</a> *pc, <a class="code" href="group__types.html#ga1bcf54cbc117a20ab2c15e59eb3a8174" title="A playlist handle.">sp_playlist</a> *pl,
                             <span class="keywordtype">int</span> position, <span class="keywordtype">void</span> *userdata)
{
    <a name="a12"></a><a class="code" href="group__playlist.html#ga62926457695bc2f2aaabe76b05eabfdd">sp_playlist_remove_callbacks</a>(pl, &amp;pl_callbacks, NULL);
}


<span class="keyword">static</span> <span class="keywordtype">void</span> container_loaded(<a class="code" href="group__types.html#ga45a2febbe167483e48dab8d606d462d7" title="A playlist container (playlist containing other playlists) handle.">sp_playlistcontainer</a> *pc, <span class="keywordtype">void</span> *userdata)
{
    fprintf(stderr, <span class="stringliteral">&quot;jukebox: Rootlist synchronized (%d playlists)\n&quot;</span>,
        <a name="a13"></a><a class="code" href="group__playlist.html#ga7a1cbf558b2b364b8249d4ce432df700">sp_playlistcontainer_num_playlists</a>(pc));
}


<span class="keyword">static</span> <a name="_a14"></a><a class="code" href="structsp__playlistcontainer__callbacks.html">sp_playlistcontainer_callbacks</a> pc_callbacks = {
    .<a name="a15"></a><a class="code" href="structsp__playlistcontainer__callbacks.html#ab1ba98e60fe050aeda8edc95166dd6fe">playlist_added</a> = &amp;playlist_added,
    .playlist_removed = &amp;playlist_removed,
    .container_loaded = &amp;container_loaded,
};


<span class="comment">/* ---------------------------  SESSION CALLBACKS  ------------------------- */</span>
<span class="keyword">static</span> <span class="keywordtype">void</span> logged_in(<a class="code" href="group__types.html#ga70dd19c6f824cf6a159575aa4c128b53" title="Representation of a session.">sp_session</a> *sess, <a class="code" href="group__error.html#gafd27986ce4cd9eeaeca8adda83c9eb6b">sp_error</a> error)
{
    <a class="code" href="group__types.html#ga45a2febbe167483e48dab8d606d462d7" title="A playlist container (playlist containing other playlists) handle.">sp_playlistcontainer</a> *pc = <a name="a16"></a><a class="code" href="group__session.html#ga319767f0b795f1c46a08390b587c5671">sp_session_playlistcontainer</a>(sess);
    <span class="keywordtype">int</span> i;

    <span class="keywordflow">if</span> (<a class="code" href="group__error.html#ggafd27986ce4cd9eeaeca8adda83c9eb6ba16cb277dc84328e4b2c0cf6d5a0c0b8d" title="No errors encountered.">SP_ERROR_OK</a> != error) {
        fprintf(stderr, <span class="stringliteral">&quot;jukebox: Login failed: %s\n&quot;</span>,
            <a name="a17"></a><a class="code" href="group__error.html#ga983dee341d3c2008830513b7cffe7bf3">sp_error_message</a>(error));
        exit(2);
    }

    <a name="a18"></a><a class="code" href="group__playlist.html#ga1338451903a81b5423cd84e37784660f">sp_playlistcontainer_add_callbacks</a>(
        pc,
        &amp;pc_callbacks,
        NULL);

    printf(<span class="stringliteral">&quot;jukebox: Looking at %d playlists\n&quot;</span>, <a class="code" href="group__playlist.html#ga7a1cbf558b2b364b8249d4ce432df700">sp_playlistcontainer_num_playlists</a>(pc));

    <span class="keywordflow">for</span> (i = 0; i &lt; <a class="code" href="group__playlist.html#ga7a1cbf558b2b364b8249d4ce432df700">sp_playlistcontainer_num_playlists</a>(pc); ++i) {
        <a class="code" href="group__types.html#ga1bcf54cbc117a20ab2c15e59eb3a8174" title="A playlist handle.">sp_playlist</a> *pl = <a name="a19"></a><a class="code" href="group__playlist.html#ga5ddd8c8064c281a14c6fd7877f522dc6">sp_playlistcontainer_playlist</a>(pc, i);

        <a class="code" href="group__playlist.html#gac90e08b7cf247c51a577ac3b763b6a6f">sp_playlist_add_callbacks</a>(pl, &amp;pl_callbacks, NULL);

        <span class="keywordflow">if</span> (!strcasecmp(<a class="code" href="group__playlist.html#ga61b7e33cc1aedb4e31a2af75ae0ac8cc">sp_playlist_name</a>(pl), g_listname)) {
            g_jukeboxlist = pl;
            try_jukebox_start();
        }
    }

    <span class="keywordflow">if</span> (!g_jukeboxlist) {
        printf(<span class="stringliteral">&quot;jukebox: No such playlist. Waiting for one to pop up...\n&quot;</span>);
        fflush(stdout);
    }
}

<span class="keyword">static</span> <span class="keywordtype">void</span> notify_main_thread(<a class="code" href="group__types.html#ga70dd19c6f824cf6a159575aa4c128b53" title="Representation of a session.">sp_session</a> *sess)
{
    pthread_mutex_lock(&amp;g_notify_mutex);
    g_notify_do = 1;
    pthread_cond_signal(&amp;g_notify_cond);
    pthread_mutex_unlock(&amp;g_notify_mutex);
}

<span class="keyword">static</span> <span class="keywordtype">int</span> music_delivery(<a class="code" href="group__types.html#ga70dd19c6f824cf6a159575aa4c128b53" title="Representation of a session.">sp_session</a> *sess, <span class="keyword">const</span> <a name="_a20"></a><a class="code" href="structsp__audioformat.html">sp_audioformat</a> *format,
                          <span class="keyword">const</span> <span class="keywordtype">void</span> *frames, <span class="keywordtype">int</span> num_frames)
{
    audio_fifo_t *af = &amp;g_audiofifo;
    audio_fifo_data_t *afd;
    <span class="keywordtype">size_t</span> s;

    <span class="keywordflow">if</span> (num_frames == 0)
        <span class="keywordflow">return</span> 0; <span class="comment">// Audio discontinuity, do nothing</span>

    pthread_mutex_lock(&amp;af-&gt;mutex);

    <span class="comment">/* Buffer one second of audio */</span>
    <span class="keywordflow">if</span> (af-&gt;qlen &gt; format-&gt;<a name="a21"></a><a class="code" href="structsp__audioformat.html#a2eb66d38a418d5c0afe284d4d45a619d" title="Audio sample rate, in samples per second.">sample_rate</a>) {
        pthread_mutex_unlock(&amp;af-&gt;mutex);

        <span class="keywordflow">return</span> 0;
    }

    s = num_frames * <span class="keyword">sizeof</span>(int16_t) * format-&gt;<a name="a22"></a><a class="code" href="structsp__audioformat.html#ab6b47d8d0ebfaab73229d707dc8bf0b8" title="Number of channels. Currently 1 or 2.">channels</a>;

    afd = malloc(<span class="keyword">sizeof</span>(audio_fifo_data_t) + s);
    memcpy(afd-&gt;samples, frames, s);

    afd-&gt;nsamples = num_frames;

    afd-&gt;rate = format-&gt;<a class="code" href="structsp__audioformat.html#a2eb66d38a418d5c0afe284d4d45a619d" title="Audio sample rate, in samples per second.">sample_rate</a>;
    afd-&gt;channels = format-&gt;<a class="code" href="structsp__audioformat.html#ab6b47d8d0ebfaab73229d707dc8bf0b8" title="Number of channels. Currently 1 or 2.">channels</a>;

    TAILQ_INSERT_TAIL(&amp;af-&gt;q, afd, link);
    af-&gt;qlen += num_frames;

    pthread_cond_signal(&amp;af-&gt;cond);
    pthread_mutex_unlock(&amp;af-&gt;mutex);

    <span class="keywordflow">return</span> num_frames;
}


<span class="keyword">static</span> <span class="keywordtype">void</span> end_of_track(<a class="code" href="group__types.html#ga70dd19c6f824cf6a159575aa4c128b53" title="Representation of a session.">sp_session</a> *sess)
{
    pthread_mutex_lock(&amp;g_notify_mutex);
    g_playback_done = 1;
    g_notify_do = 1;
    pthread_cond_signal(&amp;g_notify_cond);
    pthread_mutex_unlock(&amp;g_notify_mutex);
}


<span class="keyword">static</span> <span class="keywordtype">void</span> metadata_updated(<a class="code" href="group__types.html#ga70dd19c6f824cf6a159575aa4c128b53" title="Representation of a session.">sp_session</a> *sess)
{
    try_jukebox_start();
}

<span class="keyword">static</span> <span class="keywordtype">void</span> play_token_lost(<a class="code" href="group__types.html#ga70dd19c6f824cf6a159575aa4c128b53" title="Representation of a session.">sp_session</a> *sess)
{
    audio_fifo_flush(&amp;g_audiofifo);

    <span class="keywordflow">if</span> (g_currenttrack != NULL) {
        <a class="code" href="group__session.html#ga91f2b527a7b02d688b8ef8b24060f70a">sp_session_player_unload</a>(g_sess);
        g_currenttrack = NULL;
    }
}

<span class="keyword">static</span> <a name="_a23"></a><a class="code" href="structsp__session__callbacks.html">sp_session_callbacks</a> session_callbacks = {
    .<a name="a24"></a><a class="code" href="structsp__session__callbacks.html#a52d509962541f7d8fdd71284f40d8415">logged_in</a> = &amp;logged_in,
    .notify_main_thread = &amp;notify_main_thread,
    .music_delivery = &amp;music_delivery,
    .metadata_updated = &amp;metadata_updated,
    .play_token_lost = &amp;play_token_lost,
    .log_message = NULL,
    .end_of_track = &amp;end_of_track,
};

<span class="keyword">static</span> <a name="_a25"></a><a class="code" href="structsp__session__config.html">sp_session_config</a> spconfig = {
    .<a name="a26"></a><a class="code" href="structsp__session__config.html#a1ed9d4ff26e6f666ba96dce41d5f1bac" title="The version of the Spotify API your application is compiled with. Set to SPOTIFY_API_VERSION.">api_version</a> = <a name="a27"></a><a class="code" href="group__session.html#ga63b2309874193750ec3395f6cae32899">SPOTIFY_API_VERSION</a>,
    .cache_location = <span class="stringliteral">&quot;tmp&quot;</span>,
    .settings_location = <span class="stringliteral">&quot;tmp&quot;</span>,
    .application_key = g_appkey,
    .application_key_size = 0, <span class="comment">// Set in main()</span>
    .user_agent = <span class="stringliteral">&quot;spotify-jukebox-example&quot;</span>,
    .callbacks = &amp;session_callbacks,
    NULL,
};
<span class="comment">/* -------------------------  END SESSION CALLBACKS  ----------------------- */</span>


<span class="keyword">static</span> <span class="keywordtype">void</span> track_ended(<span class="keywordtype">void</span>)
{
    <span class="keywordtype">int</span> tracks = 0;

    <span class="keywordflow">if</span> (g_currenttrack) {
        g_currenttrack = NULL;
        <a class="code" href="group__session.html#ga91f2b527a7b02d688b8ef8b24060f70a">sp_session_player_unload</a>(g_sess);
        <span class="keywordflow">if</span> (g_remove_tracks) {
            <a name="a28"></a><a class="code" href="group__playlist.html#gabd62cd7ff9484b4c31ff7f159ec41b6a">sp_playlist_remove_tracks</a>(g_jukeboxlist, &amp;tracks, 1);
        } <span class="keywordflow">else</span> {
            ++g_track_index;
            try_jukebox_start();
        }
    }
}

<span class="keyword">static</span> <span class="keywordtype">void</span> usage(<span class="keyword">const</span> <span class="keywordtype">char</span> *progname)
{
    fprintf(stderr, <span class="stringliteral">&quot;usage: %s -u &lt;username&gt; -p &lt;password&gt; -l &lt;listname&gt; [-d]\n&quot;</span>, progname);
    fprintf(stderr, <span class="stringliteral">&quot;warning: -d will delete the tracks played from the list!\n&quot;</span>);
}

<span class="keywordtype">int</span> main(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span> **argv)
{
    <a class="code" href="group__types.html#ga70dd19c6f824cf6a159575aa4c128b53" title="Representation of a session.">sp_session</a> *sp;
    <a class="code" href="group__error.html#gafd27986ce4cd9eeaeca8adda83c9eb6b">sp_error</a> err;
    <span class="keywordtype">int</span> next_timeout = 0;
    <span class="keyword">const</span> <span class="keywordtype">char</span> *username = NULL;
    <span class="keyword">const</span> <span class="keywordtype">char</span> *password = NULL;
    <span class="keywordtype">int</span> opt;

    <span class="keywordflow">while</span> ((opt = getopt(argc, argv, <span class="stringliteral">&quot;u:p:l:d&quot;</span>)) != EOF) {
        <span class="keywordflow">switch</span> (opt) {
        <span class="keywordflow">case</span> <span class="charliteral">&#39;u&#39;</span>:
            username = optarg;
            <span class="keywordflow">break</span>;

        <span class="keywordflow">case</span> <span class="charliteral">&#39;p&#39;</span>:
            password = optarg;
            <span class="keywordflow">break</span>;

        <span class="keywordflow">case</span> <span class="charliteral">&#39;l&#39;</span>:
            g_listname = optarg;
            <span class="keywordflow">break</span>;

        <span class="keywordflow">case</span> <span class="charliteral">&#39;d&#39;</span>:
            g_remove_tracks = 1;
            <span class="keywordflow">break</span>;

        <span class="keywordflow">default</span>:
            exit(1);
        }
    }

    <span class="keywordflow">if</span> (!username || !password || !g_listname) {
        usage(basename(argv[0]));
        exit(1);
    }

    audio_init(&amp;g_audiofifo);

    <span class="comment">/* Create session */</span>
    spconfig.<a name="a29"></a><a class="code" href="structsp__session__config.html#ab10b332fe29b941162fd1d9ea1003b82" title="The size of the application key in bytes.">application_key_size</a> = g_appkey_size;

    err = <a name="a30"></a><a class="code" href="group__session.html#gaf2891f2daced4ff6da84219d6376b3aa">sp_session_create</a>(&amp;spconfig, &amp;sp);

    <span class="keywordflow">if</span> (<a class="code" href="group__error.html#ggafd27986ce4cd9eeaeca8adda83c9eb6ba16cb277dc84328e4b2c0cf6d5a0c0b8d" title="No errors encountered.">SP_ERROR_OK</a> != err) {
        fprintf(stderr, <span class="stringliteral">&quot;Unable to create session: %s\n&quot;</span>,
            <a class="code" href="group__error.html#ga983dee341d3c2008830513b7cffe7bf3">sp_error_message</a>(err));
        exit(1);
    }

    g_sess = sp;

    pthread_mutex_init(&amp;g_notify_mutex, NULL);
    pthread_cond_init(&amp;g_notify_cond, NULL);

    <a name="a31"></a><a class="code" href="group__session.html#ga3b02370d51062088a1eb6b067f66ffb6">sp_session_login</a>(sp, username, password, 0, NULL);
    pthread_mutex_lock(&amp;g_notify_mutex);

    <span class="keywordflow">for</span> (;;) {
        <span class="keywordflow">if</span> (next_timeout == 0) {
            <span class="keywordflow">while</span>(!g_notify_do)
                pthread_cond_wait(&amp;g_notify_cond, &amp;g_notify_mutex);
        } <span class="keywordflow">else</span> {
            <span class="keyword">struct </span>timespec ts;

<span class="preprocessor">#if _POSIX_TIMERS &gt; 0</span>
<span class="preprocessor"></span>            clock_gettime(CLOCK_REALTIME, &amp;ts);
<span class="preprocessor">#else</span>
<span class="preprocessor"></span>            <span class="keyword">struct </span>timeval tv;
            gettimeofday(&amp;tv, NULL);
            TIMEVAL_TO_TIMESPEC(&amp;tv, &amp;ts);
<span class="preprocessor">#endif</span>
<span class="preprocessor"></span>            ts.tv_sec += next_timeout / 1000;
            ts.tv_nsec += (next_timeout % 1000) * 1000000;

            pthread_cond_timedwait(&amp;g_notify_cond, &amp;g_notify_mutex, &amp;ts);
        }

        g_notify_do = 0;
        pthread_mutex_unlock(&amp;g_notify_mutex);

        <span class="keywordflow">if</span> (g_playback_done) {
            track_ended();
            g_playback_done = 0;
        }

        <span class="keywordflow">do</span> {
            <a name="a32"></a><a class="code" href="group__session.html#ga019a640b351de2a1ffe040ed755013f4">sp_session_process_events</a>(sp, &amp;next_timeout);
        } <span class="keywordflow">while</span> (next_timeout == 0);

        pthread_mutex_lock(&amp;g_notify_mutex);
    }

    <span class="keywordflow">return</span> 0;
}
</pre></div> </div><!-- contents -->
<hr size="1"><address style="text-align: right;"><small>
Generated on Wed Mar 28 2012 18:24:09.<br>
Copyright &copy; 2006&ndash;2012 Spotify Ltd</small></address>
</body>
</html>
